use core::{
    borrow::{Borrow, BorrowMut},
    marker::PhantomData,
    mem::{align_of, size_of},
    ptr::slice_from_raw_parts,
    usize,
};

use crate::MissAlignedError;

pub struct AlignedSlice<T: Sized + Borrow<[u8]>> {
    phantom: core::marker::PhantomData<T>,
}
impl<T: Sized + Borrow<[u8]>> AlignedSlice<T> {
    pub fn from_bytes<'a>(src: &'a [u8], len: usize) -> Option<&'a [T]> {
        if src.len() < len * size_of::<T>() {
            return None;
        }
        if (src.as_ptr() as usize) % align_of::<T>() != 0 {
            return None;
        }
        unsafe { Some(&*slice_from_raw_parts(src.as_ptr() as *const T, len)) }
    }
}

pub struct AlignedRef<T: Sized + Borrow<[u8]>> {
    phantom: core::marker::PhantomData<T>,
}
impl<T: Sized + Borrow<[u8]>> AlignedRef<T> {
    pub fn from_bytes<'a>(src: &'a [u8]) -> Option<&'a T> {
        if src.len() < core::mem::size_of::<T>() || src.as_ptr() as usize % align_of::<T>() != 0 {
            return None;
        }

        Some(unsafe { &*(src.as_ptr() as *const T) })
    }
}

pub struct AlignedSliceMut<'a, T> {
    src: &'a mut [u8],
    phantom: core::marker::PhantomData<T>,
}

impl<'a, T> AlignedSliceMut<'a, T> {
    pub fn new<const LENGTH: usize>(src: &'a mut [u8; LENGTH]) -> Result<Self, MissAlignedError>
    where
        T: BorrowMut<[u8; LENGTH]>,
    {
        if src.as_ptr() as usize % align_of::<T>() == 0 {
            Ok(Self {
                src,
                phantom: PhantomData,
            })
        } else {
            Err(MissAlignedError())
        }
    }
    /// 该函数不检查对齐，但利用编译器在编译时检查了大小。如果 src 来自于目标类型指针的转换，那么可以使用该函数。
    /// 请谨慎使用。
    pub unsafe fn unchecked_align<const LENGTH: usize>(src: &'a mut [u8; LENGTH]) -> Self
    where
        T: BorrowMut<[u8; LENGTH]>,
    {
        Self {
            src,
            phantom: PhantomData,
        }
    }
    /// 该函数虽然返回 Result，但是只检查对齐，并不利用编译器在编译时检查大小，所以是不安全的。
    pub unsafe fn unchecked_size(src: &'a mut [u8]) -> Result<Self, MissAlignedError> {
        if src.as_ptr() as usize % align_of::<T>() == 0 {
            Ok(Self {
                src,
                phantom: PhantomData,
            })
        } else {
            Err(MissAlignedError())
        }
    }
    /// 该函数既不检查对齐也不检查大小，极其不安全，需要谨慎使用，确保自己知道在干什么。
    pub unsafe fn unchecked_all(src: &'a mut [u8]) -> Self {
        Self {
            src,
            phantom: PhantomData,
        }
    }
    pub fn as_mut_ptr(&mut self) -> *mut u8 {
        self.src.as_mut_ptr()
    }
    pub fn as_ptr(&self) -> *const u8 {
        self.src.as_ptr()
    }
    pub fn as_mut(&mut self) -> &mut T {
        unsafe { &mut *(self.as_mut_ptr() as *mut T) }
    }
    pub fn as_ref(&self) -> &T {
        unsafe { &*(self.as_ptr() as *const T) }
    }
}
